package org.light.generator;

import java.util.ArrayList;
import java.util.List;

import org.light.core.Writeable;
import org.light.domain.Domain;
import org.light.domain.Field;
import org.light.domain.Statement;
import org.light.exception.ValidateException;
import org.light.utils.DomainUtil;
import org.light.utils.WriteableUtil;

public class ServerGoGenerator{
	protected String fileName = "Server.go";
	protected String packageToken;
	protected String projectName;
	protected Domain domain;
	protected boolean containsAuth = false;
	
	public ServerGoGenerator(Domain sampleDomain){
		super();
		this.projectName = sampleDomain.getProjectName();
		this.packageToken = sampleDomain.getPackageToken();
		this.domain = sampleDomain;
	}

	public String generateString() throws ValidateException{
		List<Writeable> sList = new ArrayList<Writeable>();
		sList.add(new Statement(1000L,0,"package main"));
		sList.add(new Statement(2000L,0,""));
		sList.add(new Statement(2500L,0,"import ("));
		sList.add(new Statement(4000L,1,"\""+DomainUtil.packagetokenToGoPackageFolder(this.getProjectName(),"config")+"\""));
		sList.add(new Statement(5000L,1,"\""+DomainUtil.packagetokenToGoPackageFolder(this.getProjectName(),"database")+"\""));
		sList.add(new Statement(6000L,1,"\""+DomainUtil.packagetokenToGoPackageFolder(this.getProjectName(),"router")+"\""));		
		sList.add(new Statement(7000L,1,"\""+DomainUtil.packagetokenToGoPackageFolder(this.getProjectName(),"middlewares")+"\""));	
		
		sList.add(new Statement(9000L,1,"\"log\""));
		sList.add(new Statement(10000L,0,""));
		sList.add(new Statement(11000L,1,"\"github.com/gin-gonic/gin\""));
		sList.add(new Statement(12000L,1,"\"github.com/spf13/viper\""));
		if (this.containsAuth) {
			sList.add(new Statement(12100L,1,"\""+DomainUtil.packagetokenToGoPackageFolder(this.getProjectName(),this.domain.getControllerSuffix())+"\""));
			sList.add(new Statement(12200L,1,"\""+DomainUtil.packagetokenToGoPackageFolder(this.getProjectName(),"interceptor")+"\""));
			sList.add(new Statement(12400L,1,"\"fmt\""));
			sList.add(new Statement(12500L,1,"\"html/template\""));
			sList.add(new Statement(12600L,1,"\"net/http\""));
			sList.add(new Statement(12700L,1,"\"time\""));
			sList.add(new Statement(12800L,0,""));
			sList.add(new Statement(12900L,1,"session \"github.com/ScottHuangZL/gin-jwt-session\""));
		}
		
		sList.add(new Statement(13000L,0,")"));
		sList.add(new Statement(14000L,0,""));

		sList.add(new Statement(15000L,0,"func main() {"));
		sList.add(new Statement(16000L,1,"if err := config.Init(); err != nil {"));
		sList.add(new Statement(17000L,2,"panic(err)"));
		sList.add(new Statement(18000L,1,"}"));
		sList.add(new Statement(19000L,0,""));
		sList.add(new Statement(20000L,1,"if err := database.Init(); err != nil {"));
		sList.add(new Statement(21000L,2,"panic(err)"));
		sList.add(new Statement(22000L,1,"}"));
		sList.add(new Statement(23000L,0,""));
		sList.add(new Statement(24000L,1,"g := gin.Default()"));
		sList.add(new Statement(24100L,1,"g.Use(middlewares.Cors())"));
		sList.add(new Statement(25000L,0,""));
		sList.add(new Statement(26000L,1,"g.GET(\"/\", func(c *gin.Context) {"));
		sList.add(new Statement(27000L,2,"c.HTML(200, \"index.html\", nil)"));
		sList.add(new Statement(28000L,1,"})"));
		sList.add(new Statement(29000L,0,""));
		if (this.containsAuth) {
			sList.add(new Statement(30000L,1,"g.Static(\"/login\", \"./template/login\")"));
			sList.add(new Statement(31000L,1,"g.GET(\"/indexController/loginIndex\", controller.LoginIndex)"));
		}
		sList.add(new Statement(32000L,0,""));
		sList.add(new Statement(33000L,1,"g.Static(\"/css\", \"./template/css\")"));
		sList.add(new Statement(34000L,1,"g.Static(\"/images\", \"./template/images\")"));
		sList.add(new Statement(35000L,1,"g.Static(\"/js\", \"./template/js\")"));
		sList.add(new Statement(36000L,1,"g.Static(\"/uploadjs\", \"./template/uploadjs\")"));
		sList.add(new Statement(37000L,1,"g.Static(\"/easyui\", \"./template/easyui\")"));
		sList.add(new Statement(38000L,1,"g.Static(\"/echarts\", \"./template/echarts\")"));
		sList.add(new Statement(39000L,0,""));
		sList.add(new Statement(40000L,1,"g.LoadHTMLFiles(\"./template/index.html\")"));
		long serial = 41000L;
		if (this.containsAuth) {
			sList.add(new Statement(serial,1,"g.POST(\"/login"+this.domain.getControllerNamingSuffix()+"/register"+this.domain.getCapFirstDomainName()+"\", "+this.domain.getControllerSuffix()+".Register"+this.domain.getCapFirstDomainName()+")"));
			sList.add(new Statement(serial+1000L,1,"g.GET(\"/login"+this.domain.getControllerNamingSuffix()+"/readMySession\", "+this.domain.getControllerSuffix()+".ReadMySession)"));
			
			serial += 2000L;
			for (Field f:this.domain.getPlainFields()) {
				if (f.getFieldType().equalsIgnoreCase("image")) {
					sList.add(new Statement(serial,1,"g.POST(\"/login"+this.domain.getControllerNamingSuffix()+"/addUpload"+this.domain.getCapFirstDomainName()+f.getCapFirstFieldName()+"\", "+this.domain.getControllerSuffix()+".AddUpload"+this.domain.getCapFirstDomainName()+f.getCapFirstFieldName()+")"));
					serial += 1000L;
				}
			}
			sList.add(new Statement(serial+1000L,1,"g.POST(\"/login"+this.domain.getControllerNamingSuffix()+"/login"+this.domain.getCapFirstDomainName()+"\", "+this.domain.getControllerSuffix()+".Login"+this.domain.getCapFirstDomainName()+")"));
		}
		
		serial += 2000L;
		sList.add(new Statement(serial,1,"//session.SecretKey = \"JerryJwtSession\""));
		if (this.containsAuth) {
			sList.add(new Statement(serial+1000L,1,"session.NewStore()"));
			sList.add(new Statement(serial+2000L,1,"g.Use(session.ClearMiddleware()) //important to avoid mem leak"));
			sList.add(new Statement(serial+3000L,1,"setupRouter(g)"));
			sList.add(new Statement(serial+4000L,0,""));
		}
		sList.add(new Statement(serial+5000L,1,"// Set gin mode."));
		sList.add(new Statement(serial+6000L,1,"gin.SetMode(viper.GetString(\"runmode\"))"));

		if (this.containsAuth) {
			sList.add(new Statement(serial+7000L,1,"g.Use(interceptor.LoginInterceptor())"));
			sList.add(new Statement(serial+8000L,1,"g.Static(\"/pages\", \"./template/pages\")"));
		}
		sList.add(new Statement(serial+9000L,0,""));
		sList.add(new Statement(serial+10000L,1,"router.InitRouter(g)"));
		sList.add(new Statement(serial+11000L,1,"if err := g.Run(viper.GetString(\"addr\")); err != nil {"));
		sList.add(new Statement(serial+12000L,2,"log.Fatal(\"ListenAndServe:\", err)"));
		sList.add(new Statement(serial+13000L,1,"}"));
		sList.add(new Statement(serial+14000L,0,"}"));
		sList.add(new Statement(serial+15000L,0,""));
		sList.add(new Statement(serial+16000L,0,"func setupRouter(r *gin.Engine) {"));
		sList.add(new Statement(serial+17000L,1,"r.Delims(\"{%\", \"%}\")"));
		sList.add(new Statement(serial+18000L,1,"// Default With the Logger and Recovery middleware already attached"));
		sList.add(new Statement(serial+19000L,1,"// Set a lower memory limit for multipart forms (default is 32 MiB)"));
		sList.add(new Statement(serial+20000L,1,"r.MaxMultipartMemory = 8 << 20 // 8 MiB"));
		sList.add(new Statement(serial+21000L,1,"//r.Static(\"/static\", \"./static\")"));
		sList.add(new Statement(serial+22000L,1,"r.SetFuncMap(template.FuncMap{"));
		sList.add(new Statement(serial+23000L,2,"\"formatAsDate\": FormatAsDate,"));
		sList.add(new Statement(serial+24000L,1,"})"));
		sList.add(new Statement(serial+25000L,0,""));
		
		sList.add(new Statement(serial+26000L,1,"r.GET(\"/login"+this.domain.getControllerNamingSuffix()+"/logout"+this.domain.getCapFirstDomainName()+"\", "+this.domain.getControllerSuffix()+".LoginIndex)"));
		sList.add(new Statement(serial+27000L,1,"r.GET(\"/index"+this.domain.getControllerNamingSuffix()+"/homeIndex\", "+this.domain.getControllerSuffix()+".HomeIndex)"));
		sList.add(new Statement(serial+28000L,1,"r.GET(\"/index.html\", "+this.domain.getControllerSuffix()+".HomeIndex)"));
		sList.add(new Statement(serial+29000L,1,"r.GET(\"/login"+this.domain.getControllerNamingSuffix()+"/ping\", func(c *gin.Context) {"));
		sList.add(new Statement(serial+30000L,2,"c.JSON(http.StatusOK, gin.H{\"ping\": \"pong\"})"));
		sList.add(new Statement(serial+31000L,1,"})"));
		sList.add(new Statement(serial+32000L,0,""));
		sList.add(new Statement(serial+33000L,0,"}"));
		sList.add(new Statement(serial+34000L,0,""));
		sList.add(new Statement(serial+35000L,0,"//FormatAsDate return a yyyy-mm-dd date"));
		sList.add(new Statement(serial+36000L,0,"func FormatAsDate(t time.Time) string {"));
		sList.add(new Statement(serial+37000L,1,"year, month, day := t.Date()"));
		sList.add(new Statement(serial+38000L,1,"return fmt.Sprintf(\"%d-%02d-%02d\", year, month, day)"));
		sList.add(new Statement(serial+39000L,0,"}"));

		return WriteableUtil.merge(sList).getContent();
	}

	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public String getPackageToken() {
		return packageToken;
	}

	public void setPackageToken(String packageToken) {
		this.packageToken = packageToken;
	}

	public String getProjectName() {
		return projectName;
	}

	public void setProjectName(String projectName) {
		this.projectName = projectName;
	}

	public boolean isContainsAuth() {
		return containsAuth;
	}

	public void setContainsAuth(boolean containsAuth) {
		this.containsAuth = containsAuth;
	}

	public Domain getDomain() {
		return domain;
	}

	public void setDomain(Domain domain) {
		this.domain = domain;
	}

}
